/*
 *  Copyright 2015-2016, RenGu Technology (BeiJing) Co., Ltd.
 *  All right reserved.
 *
 *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF RENGU TECHNOLOGY (BeiJing) CO., LTD.
 *
 *  THE CONTENTS OF THIS FILE MAY NOT BE DISCLOSED TO THIR PARTIES,
 *  COPIED OR DUPLICATED IN ANY FORM, IN WHOLE OR IN PART,
 *  WITHOUT THE PRIOR WRITTEN PERMISSION OF RENGU TECHNOLOGY (BeiJing) CO., LTD.
 *
 *  Check3o1
 *
 *  Edit History:
 *      lizhangtao Created on 2020年04月12日
 *
 */
package cc.rengu.igas.acct.common.util;

import cc.rengu.igas.acct.common.entity.AcctDetail;
import cc.rengu.igas.acct.common.entity.AcctInfo;
import cc.rengu.igas.acct.common.enums.AcctRespCodeEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.utility.base.AmountUtil;
import cc.rengu.utility.base.StringUtil;
import cc.rengu.utility.log.RgLogger;

import java.math.BigDecimal;

/**
 * 三选一检查
 *
 * @author lizhangtao
 * @version 1.0
 * @date 2020/5/8
 */
public class CheckAcct3o1 {

    /**
     * 检查请求，账户号、客户id，外部用户类型&外部用户id必须三选一，交易金额必须上送
     *
     * @param acctNo     账户号
     * @param customerId 客户id
     * @param userType   外部用户类型
     * @param userId     外部用户id
     * @param transAmt   交易金额，以元为单位
     */
    public static void checkReq(String acctNo, String customerId, String userType, String userId, String transAmt, RgLogger rglog) throws BizException {
        if (StringUtil.isNullorEmpty(acctNo) &&
                StringUtil.isNullorEmpty(customerId) &&
                (StringUtil.isNullorEmpty(userType) || StringUtil.isNullorEmpty(userId))) {
            rglog.error("账户号、客户id，外部用户类型&外部用户id必须三选一");
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        } else {
            //交易金额最多三位小数，三位小数以下则报错
            //交易金额必须全部为数字或者小数点
            //检查交易金额格式，可以不存在小数点，存在小数点（小数点后一位，小数点后两位，小数点后三位）
            try {
                checkAcctAmt(transAmt);
            } catch (BizException e) {
                rglog.error(e.getMessage());
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            } catch (Exception e) {
                rglog.error(StringUtil.ExceptionToString(e));
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
        }
    }

    /**
     * 检查请求和数据库是否一致
     *
     * @param acctNo     账号，请求存在则检查
     * @param customerId 客户号，请求存在则检查
     * @param userType   外部用户类型，请求存在则检查
     * @param userId     外部用户ID，请求存在则检查，
     * @param acctInfo   数据库中账户信息对象
     * @param rglog      日志句柄
     * @throws BizException 业务异常
     * @throws Exception    其他异常
     */
    public static void checkReqWithDb(String acctNo, String customerId, String userType, String userId, AcctInfo acctInfo, RgLogger rglog) throws BizException, Exception {
        //使用账号查询到账户信息，若外部用户类型&客户标识上送了也不检查,若客户号上送则检查
        if (!StringUtil.isNullorEmpty(acctNo)) {
            if (!StringUtil.isNullorEmpty(customerId) && !customerId.equals(acctInfo.getCustomerId())) {
                //客户号上送错误
                rglog.error("账号<{}>客户号<{}>不匹配", acctNo, customerId);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
            if (!StringUtil.isNullorEmpty(userType) && !userType.equals(acctInfo.getUserType())) {
                //外部用户类型上送错误
                rglog.error("账号<{}>与外部用户类型不匹配<{}>", acctNo, userType);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
            if (!StringUtil.isNullorEmpty(userId) && !userId.equals(acctInfo.getUserId())) {
                //外部用户类型上送错误
                rglog.error("账号<{}>与用户标识不匹配<{}>", acctNo, userId);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
        }
        //不上送账号使用客户号查询
        else if (!StringUtil.isNullorEmpty(customerId)) {
            if (!StringUtil.isNullorEmpty(userType) && !userType.equals(acctInfo.getUserType())) {
                //外部用户类型上送错误
                rglog.error("客户号<{}>与外部用户类型不匹配<{}>", customerId, userType);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
            if (!StringUtil.isNullorEmpty(userId) && !userId.equals(acctInfo.getUserId())) {
                //外部用户类型上送错误
                rglog.error("客户号<{}>与用户标识不匹配<{}>", customerId, userId);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
        }
        //使用外部用户类型与用户标识查询
        else if (!StringUtil.isNullorEmpty(userType) && !StringUtil.isNullorEmpty(userId)) {
            //不需要检查其他项
            rglog.debug("检查通过");
        } else {
            rglog.error("账号|客户号|外部用户类型&用户标识至少上送其一！");
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
    }

    /**
     * 原交易检查，上送的金额及账户等信息必须与原交易一致
     *
     * @param acctNo     请求的账户号
     * @param customerId 请求的客户号
     * @param userType   请求的外部用户类型
     * @param userId     请求的外部用户id
     * @param transAmt   请求的交易金额
     * @param acctDetail 原交易信息
     * @param rglog      日志句柄
     */
    public static void origTrans(String acctNo, String customerId, String userType, String userId, String transAmt,
                                 AcctDetail acctDetail, RgLogger rglog) {
        //若上送账号则检查
        if (!StringUtil.isNullorEmpty(acctNo) && !acctNo.equals(acctDetail.getAcctNo())) {
            rglog.error("上送的账号<{}>与原交易的账户不一致", acctNo);
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        //若上送客户号则检查
        if (!StringUtil.isNullorEmpty(customerId) && !customerId.equals(acctDetail.getCustomerId())) {
            rglog.error("上送的客户号<{}>与原交易的客户号不一致", customerId);
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        //若上送外部用户id或者外部用户类型则检查
        if (!StringUtil.isNullorEmpty(userId) || !StringUtil.isNullorEmpty(userType)) {
            if (StringUtil.isNullorEmpty(userType) || StringUtil.isNullorEmpty(userId)) {
                rglog.error("外部用户id和外部用户类型必须同时出现");
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            } else if (!userId.equals(acctDetail.getUserId())) {
                rglog.error("上送外部用户id<{}>与原交易不一致", userId);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            } else if (!userType.equals(acctDetail.getUserType())) {
                rglog.error("上送外部用户类型<{}>与原交易不一致", userType);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            } else {
                //其他为检查通过
                rglog.debug("用户类型及id检查通过");
            }
        }
        //检查交易金额
        if (!StringUtil.isNullorEmpty(transAmt)) {
            AmountUtil amountUtil1 = new AmountUtil(transAmt);
            AmountUtil amountUtilOrig = new AmountUtil(acctDetail.getTransAmt());
            if (0 != AmountUtil.compare(amountUtil1, amountUtilOrig)) {
                rglog.error("上送的交易金额<{}>与原交易金额不一致", transAmt);
                throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
            }
        } else {
            rglog.error("上送的交易金额为空<{}>与原交易金额不一致", transAmt);
            throw new BizException(AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespCode(), AcctRespCodeEnum.MSG_VALID_CHECK_ERROR.getRespDesc());
        }
        rglog.debug("原交易检查通过");

    }

    private static void checkAcctAmt(String amt) throws BizException {
        if (cc.rengu.oltp.utility.util.StringUtil.isEmptyOrNull(amt)) {
            throw new BizException("金额[" + amt + "]非法");
        }
        BigDecimal bigDecimal;
        try {
            bigDecimal = new BigDecimal(amt);
        } catch (NumberFormatException e) {
            throw new BizException("金额[" + amt + "]非法");
        }
        if (0 == bigDecimal.compareTo(BigDecimal.ZERO)) {
            throw new BizException("金额[" + amt + "]不允许为0");
        }
        if (bigDecimal.scale() > 3) {
            throw new BizException("金额[" + amt + "]精度大于3");
        }
        bigDecimal = bigDecimal.setScale(3);
        amt = bigDecimal.toString();
        if (amt.startsWith("-")) {
            throw new BizException("金额[" + amt + "]不允许为负数");
        }
    }
}
